// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: declaration of CFactory.
//   $Id$



// Factory.h: Definition of the CFactory class
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_FACTORY_H__C740A353_DFA3_46FE_9EEF_8FB21350F4CD__INCLUDED_)
#define AFX_FACTORY_H__C740A353_DFA3_46FE_9EEF_8FB21350F4CD__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "resource.h"       // main symbols

#include "FormControl.h"
#include <Common/COM/msw/MultiIDispatch.h>
#include <map>
#include <list>
#include "EventTargetDispatch.h"
class CXFormsXFormsElement;

struct ElementIsDifferent : public std::binary_function <CComQIPtr<IHTMLElement>,CComQIPtr<IHTMLElement>, bool> 
   {
      bool operator()(
         const CComPtr<IHTMLElement>& _Left, 
         const CComPtr<IHTMLElement>& _Right
      ) const
	  {
			CComPtr<IUnknown> l, r;
			_Left.QueryInterface(&l);
			_Right.QueryInterface(&r);
		  return l.p < r.p;
	  };
   };

enum FindBehaviourPermission
{
	NONE,
	ACTIONS,
	FORCE,
	REFUSE,
	SELECT_CHILD
};

typedef std::pair<CComQIPtr<IHTMLElement>, FindBehaviourPermission> CPairHTMLElementAndFindBehaviourPermission;
typedef std::list<CPairHTMLElementAndFindBehaviourPermission> CListOfHTMLElementsAndFindBehaviourPermissions;

typedef  HRESULT (__stdcall*ObjectCreationFunctionPtr)(IUnknown** ) ;
typedef std::map<CComBSTR, ObjectCreationFunctionPtr > CMapCComBSTRToObjectCreationFunction;
typedef std::pair<CComBSTR, ObjectCreationFunctionPtr > CPairCComBSTRToObjectCreationFunction;

typedef std::pair<ObjectCreationFunctionPtr,FindBehaviourPermission> CPairObjectCreationData;
typedef std::pair<CComBSTR,CPairObjectCreationData> CPairCComBSTRToObjectCreationData;
typedef std::map<CComBSTR, CPairObjectCreationData > CMapCComBSTRToObjectCreationData;

typedef IDispatchImpl<IFactory,&IID_IFactory,&LIBID_XFORMSLib> FactoryDispatch;
typedef IDispatchImpl<IEventNotification,&IID_IEventNotification,&LIBID_XFORMSLib> EventNotificationDispatch;

class CFactory;
typedef CMultiIDispatch<CFactory> CFactoryMultiIDispatch;
/////////////////////////////////////////////////////////////////////////////
// CFactory
//TODO: implement Singleton pattern.
class CFactory :
	public ISupportErrorInfo,
	public CComObjectRoot,
	public IObjectSafetyImpl<CFactory, INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA>,
	public CComCoClass<CFactory,&CLSID_Factory>,

	public FactoryDispatch,
	public EventNotificationDispatch,
	public EventTargetDispatch,

	// Interfaces added to implement a binary element behavior factory.
	public IElementBehaviorFactory,
	public IElementNamespaceFactory,
	public IElementNamespaceFactoryCallback,
	public IPersistPropertyBag,
	public CFactoryMultiIDispatch
{
public:
	CFactory();
	virtual ~CFactory();

	DECLARE_MULTI_DISPATCH(CFactory)

	BEGIN_MULTI_DISPATCH_MAP(CFactory)
		MULTI_DISPATCH_ENTRY(FactoryDispatch)
		MULTI_DISPATCH_ENTRY(EventNotificationDispatch)
		MULTI_DISPATCH_ENTRY(EventTargetDispatch)
	END_MULTI_DISPATCH_MAP()         

#ifdef _DEBUG
	ULONG InternalRelease( void)
	{
		ULONG l = __super::InternalRelease();
		return l;
	}

	ULONG InternalAddRef()
	{
		ULONG l = __super::InternalAddRef();
		return l;
	}
#endif

	//	IDispatch
	//	STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid ); 
	//	STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
	//			DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr);

	// IElementBehaviorFactory
	STDMETHOD(FindBehavior)(BSTR bstrBehavior, BSTR bstrBehaviorUrl, IElementBehaviorSite* pSite,
		IElementBehavior** ppBehavior);

	// IElementNamespaceFactory
	STDMETHOD(Create)(IElementNamespace * pNamespace);

	// IElementNamespaceFactoryCallback
	STDMETHOD(Resolve)(BSTR bstrNamespace, BSTR bstrTagName, BSTR bstrAttrs,
		IElementNamespace* pNamespace);

	// IObjectSafety
	STDMETHOD(SetInterfaceSafetyOptions)(REFIID/* riid*/,
		DWORD dwOptionSetMask, DWORD dwEnabledOptions)
	{
		// Set the safety options we have been asked to set.
		m_dwCurrentSafety = m_dwCurrentSafety  & ~dwEnabledOptions | dwOptionSetMask;
		return S_OK;
	} 
        virtual HRESULT STDMETHODCALLTYPE GetClassID( 
			/* [out] */ CLSID *pClassID){*pClassID = CLSID_NULL; return S_FALSE;};

	//IPersistPropertyBag
	BOOL m_bRequiresSave;
	virtual HRESULT STDMETHODCALLTYPE InitNew( void)
	{
		return S_OK;
	};
    
    virtual HRESULT STDMETHODCALLTYPE Load( 
        /* [in] */ IPropertyBag *pPropBag,
		/* [in] */ IErrorLog *pErrorLog);
    
    virtual HRESULT STDMETHODCALLTYPE Save( 
        /* [in] */ IPropertyBag * /*pPropBag*/,
        /* [in] */ BOOL /*fClearDirty*/,
		/* [in] */ BOOL /*fSaveAllProperties*/)
	{
		return S_OK;
	}
      
	HRESULT FinalConstruct(void);
	void FinalRelease(void);

	DECLARE_GET_CONTROLLING_UNKNOWN()
	DECLARE_PROTECT_FINAL_CONSTRUCT()

	BEGIN_COM_MAP(CFactory)
		COM_INTERFACE_ENTRY2(IDispatch, IFactory)
		COM_INTERFACE_ENTRY(IFactory)
		COM_INTERFACE_ENTRY(IEventNotification)
		COM_INTERFACE_ENTRY(IPersistPropertyBag)
		COM_INTERFACE_ENTRY_AUTOAGGREGATE(IID_IEventTarget,m_pEventTarget.p,CLSID_EventTarget)
		COM_INTERFACE_ENTRY(ISupportErrorInfo)
		COM_INTERFACE_ENTRY(IObjectSafety)
		COM_INTERFACE_ENTRY(IElementBehaviorFactory)
		COM_INTERFACE_ENTRY(IElementNamespaceFactory)
		COM_INTERFACE_ENTRY(IElementNamespaceFactoryCallback)
	END_COM_MAP()
	//DECLARE_NOT_AGGREGATABLE(CFactory) 
	// Remove the comment from the line above if you don't want your object to 
	// support aggregation. 

	DECLARE_REGISTRY_RESOURCEID(IDR_Factory)
	// ISupportsErrorInfo
	STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

	// IFactory
	STDMETHOD(GetDebugAgent)(IXFormsDebugAgent **ppDebugAgent);
	//STDMETHOD(GetConfigHandler)(IConfigHandler **ppConfigHandler);
	
	STDMETHOD(SetFindBehaviourResponseWithin)(IUnknown * pEl, short response);
	STDMETHOD(UnsetFindBehaviourResponseWithin)(IUnknown * pEl);

	//IEventTarget
	STDMETHOD(addEventListener)(BSTR type, IEventListener * listener, BOOL useCapture);
	STDMETHOD(removeEventListener)(BSTR type, IEventListener * listener, BOOL useCapture);
	STDMETHOD(dispatchEvent)(IDOMEvent * evt,BOOL * bCancelled);

	// IEventNotification
	STDMETHOD(get_EnableEventNotification)(VARIANT_BOOL *pbEnableEventNotification);
	STDMETHOD(put_EnableEventNotification)(VARIANT_BOOL bEnableEventNotification);

private:
	bool ShouldThisFindBehaviourRequestBeRefused(IElementBehaviorSite * pSite,const BSTR bstrBehavior);
	CListOfHTMLElementsAndFindBehaviourPermissions m_RefusalList;

	static CMapCComBSTRToObjectCreationData m_ObjectCreationMap;
	static HANDLE sm_hObjectCreationMapMutex;
	static CMapCComBSTRToObjectCreationFunction m_ActionObjectCreationMap;
	static HANDLE sm_hActionObjectCreationMapMutex;
	//static CMapPtrToPtr m_MapFormToModel;
	//static CMapPtrToPtr m_MapModelToElement;

	//<summary>
	//	Without this function, this SetAt would be a messy two line affair
	//	as it involves a slightly convoluted cast for the function pointer.
	//</summary>
	//<param name="sName">The name of the element whose object this function creates.</param>
	//<param name="fn">The function used to create objects for the element namede in sName</param>
	static void RegisterCreationFunction(const wchar_t * const sName,ObjectCreationFunctionPtr fn,FindBehaviourPermission p);
	static void RegisterActionFunction(const wchar_t * const sName,ObjectCreationFunctionPtr fn);

	CComPtr<IEventTarget> m_pEventTarget;
	//<summary>Identifies the form for which this is a control factory</summary>
	LONG m_lFormId;
	//<summary>form to which this object is a control factory</summary>
	CXFormsXFormsElement * m_pForm;

	static CComPtr<IClassFactory> sm_pDebugAgentFactory;
	static HANDLE sm_hDebugAgentFactoryMutex;
	static HRESULT CreateDebugAgentFactory(void);
	HRESULT ResolveForm(IHTMLElement *pEl);
};

OBJECT_ENTRY_AUTO(__uuidof(Factory), CFactory)

#endif // !defined(AFX_FACTORY_H__C740A353_DFA3_46FE_9EEF_8FB21350F4CD__INCLUDED_)
